package com.lw.rw;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author LW
 * @2020/8/20 13:41
 */

/**
 * 独占锁（写锁）    一次只能被一个线程占用
 * 共享锁（读锁）     多个线程可以同时占有
 *ReadWriteLock读写锁
 * 读-读   可以共存
 * 读-写    不能共存
 * 写-写     更不能共存
 */
public class ReadWriteLockDemo {

    public static void main(String[] args) {
        MyCacheLock myCache = new MyCacheLock();
        //写入
        for (int i = 1; i <= 10; i++) {
            int temp=i;
            new Thread(()->{
                myCache.put(temp+"",temp+"");
            },String.valueOf(i)).start();
        }
        for (int i = 1; i <= 10; i++) {
            int temp=i;
            new Thread(()->{
                myCache.get(temp+"");
            },String.valueOf(i)).start();
        }

    }
}

class MyCacheLock{

    //读写锁：更加细粒度的控制
    ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();

    private volatile Map<String ,Object> map = new HashMap<>();

    //存，写
    public void put(String key,Object value){
        rwlock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"---写入---"+key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName()+"---写入成功！---");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwlock.writeLock().unlock();
        }

    }
    //    -----------读锁也必须加-----在读取结束之前不允许写锁的加入
    //取，读
    public void get(String key){
        rwlock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"读取"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"读取成功!");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            rwlock.readLock().unlock();
        }

    }
}

/**
 * 自定义缓存
 */
class MyCache{
    /**volatile 共享资源同步
     * 只能保证可见性（有序性）， 不能保证原子性
     */

    private volatile Map<String ,Object> map = new HashMap<>();

    //存，写
    public void put(String key,Object value){
        System.out.println(Thread.currentThread().getName()+"写入"+key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName()+"写入成功！");

    }
    //取，读
    public void get(String key){
        System.out.println(Thread.currentThread().getName()+"读取"+key);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"读取成功!");
    }
}